package com.codegeek.project.slope.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.codegeek.common.utils.DateUtils;
import com.codegeek.common.utils.poi.ExcelUtil;
import com.codegeek.framework.aspectj.lang.annotation.Log;
import com.codegeek.framework.aspectj.lang.enums.BusinessType;
import com.codegeek.framework.web.controller.BaseController;
import com.codegeek.framework.web.domain.AjaxResult;
import com.codegeek.framework.web.page.TableDataInfo;
import com.codegeek.project.communicate.RedisDBService;
import com.codegeek.project.slope.domain.*;
import com.codegeek.project.slope.service.ISlopeItemHistoryService;
import com.codegeek.project.slope.service.impl.SlopeMonitorItemServiceImpl;
import com.codegeek.project.slope.service.impl.SlopeSensorServiceImpl;
import com.codegeek.project.system.domain.SysDictData;
import com.codegeek.project.system.service.ISysDictDataService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 监测项历史数据Controller
 *
 * @author codegeek
 * @date 2020-02-17
 */
@RestController
@RequestMapping("/slope/history")
@Api(value = "监测项历史数据Controller", tags = {"监测项历史数据操作接口"})
public class SlopeItemHistoryController extends BaseController {
    @Autowired
    private ISlopeItemHistoryService slopeItemHistoryService;

    /**
     * 查询监测项历史数据列表
     */
    @ApiOperation("查询监测项历史数据列表")
    @GetMapping("/list")
    @PreAuthorize("@ss.hasPermi('slope:history:list')")
    public TableDataInfo list(SlopeItemHistory slopeItemHistory) {
        startPage();
        List<SlopeItemHistory> list = slopeItemHistoryService.selectSlopeItemHistoryList(slopeItemHistory);
        return getDataTable(list);
    }

    /**
     * 查询监测项历史数据列表
     */
    @ApiOperation("查询监测项历史数据列表通过传感器信息查询")
    @GetMapping("/listBySensor")
    @PreAuthorize("@ss.hasPermi('slope:history:listBySensor')")
    public TableDataInfo listBySensor(SlopeItemHistory slopeItemHistory) {
        startPage();
        List<SlopeItemHistory> list = slopeItemHistoryService.selectSlopeItemHistoryList(slopeItemHistory);
        return getDataTable(list);
    }


    @Autowired
    SlopeSensorServiceImpl slopeSensorService;
    @Autowired
    SlopeMonitorItemServiceImpl slopeMonitorItemService;

    @Autowired
    NamedParameterJdbcTemplate jdbcTemplate;

    @ApiOperation("查询监历史数据列表__数据报表")
    @GetMapping("/listBySensor1")
    @PreAuthorize("@ss.hasPermi('slope:history:listBySensor1')")
    public AjaxResult listBySensor1(SlopeItemHistory slopeItemHistory) {
        Map<String, Object> map = new HashMap<>();
        SlopeMonitorItem item = new SlopeMonitorItem();
        item.setSensorType(slopeItemHistory.getSensorType());
        item.setState(slopeItemHistory.getStatusOption());
        item.setDeviceName(slopeItemHistory.getDeviceName());
        List<SlopeMonitorItem> list = slopeMonitorItemService.selectSlopeMonitorItemList(item);
        String ids = "";
        HashSet<Long> idSet = new HashSet<>();
        List<Map<String, Object>> returnList = new LinkedList<>();//返回的list对象
        for (SlopeMonitorItem monitorItem : list) {
            idSet.add(monitorItem.getSensorId());
        }
        for (Long id : idSet) {
            ids += id + ",";
        }
        if (ids.length() > 0) {
            ids = ids.substring(0, ids.length() - 1);
            for (String id : ids.split(",")) {
                Map<String, Object> returnMap = handleHistoryItemMap(Long.valueOf(id), slopeItemHistory.getBeginTime(), slopeItemHistory.getEndTime());
                if (returnMap != null) {
                    returnList.add(returnMap);
                }
            }
        }
        map.put("historyData", returnList);
        map.put("monitorItem", list);
        return AjaxResult.success(map);

    }

    /**
     * 查询监测项历史数据列表__数据报表，数据需要归类计算处理
     *
     * @return arr:
     * [
     * {
     * keywords: "GNSS监测仪2",
     * type: "GNSS",
     * content: "表面位移",
     * status: "在线",
     * number: "GNSS-01",
     * site: "33.3345678  127.156487",
     * grid: [
     * {
     * time: "2020-01-21 00:00:00",
     * XSkewing: 12,
     * YSkewing: 1,
     * HSkewing: 2,
     * horizontalSkewing: 2,
     * transverseSkewing: 3
     * }
     * ]
     * }
     * ]
     */
    @ApiOperation("查询监测项历史数据列表__监测数据")
    @GetMapping("/listBySensor2")
    @PreAuthorize("@ss.hasPermi('slope:history:listBySensor2')")
    public TableDataInfo listBySensor2(SlopeItemHistory slopeItemHistory) {
        startPage();
        String ids = slopeItemHistory.getSensorIdArr();
        List<Map<String, Object>> returnList = new LinkedList<>();//返回的list对象
        for (String id : ids.split(",")) {
            Map<String, Object> returnMap = handleHistoryItemMap(Long.valueOf(id), slopeItemHistory.getBeginTime(), slopeItemHistory.getEndTime());
            returnList.add(returnMap);
        }
        return getDataTable(returnList);
    }


    @ApiOperation("查询监测项历史数据列表__单个监测项")
    @GetMapping("/listHistoryByItem")
    @PreAuthorize("@ss.hasPermi('slope:history:listHistoryByItem')")
    public AjaxResult listHistoryByItem(Long id, String sensorType, String begin, String end) {
        return AjaxResult.success(handleHistoryArrByItem(id, sensorType, begin, end));
    }

    @ApiOperation("查询监测项历史数据列表__单个传感器")
    @GetMapping("/listBySensorId")
    @PreAuthorize("@ss.hasPermi('slope:history:listBySensorId')")
    public AjaxResult listBySensorId(Long id, String begin, String end) {
        return AjaxResult.success(handleHistoryItemMap(id, begin, end));
    }


    /**
     * @param id 当前查询的sensor id
     * @return 每个sensor所包装的结果集对象，包括传感器附带的基本信息，和生产表格和chart的数据
     */
    public Map<String, Object> handleHistoryItemMap(Long id, String begin, String end) {
        Map<String, Object> returnMap = new HashMap<>();//返回的list中每个map对象
        SlopeSensor sensor = slopeSensorService.selectSlopeSensorByIdWithoutIsValid(id);//查询sensor
        if (sensor == null) {
            return null;
        }
        //开始赋予传感器基本属性
        String deviceName = sensor.getDevice().getDeviceName();
        returnMap.put("keywords", deviceName);
        String sensorType = sensor.getSensorType().getTypeName();
        returnMap.put("type", sensorType);
        String monitorDetail = sensor.getMonitorDetail();
        returnMap.put("content", monitorDetail);
        int deviceState = sensor.getDevice().getState();
        String state = deviceState == 1 ? "正常" : deviceState == 0 ? "离线" : "维护";
        returnMap.put("status", state);
        String number = sensor.getDevice().getNumber();
        returnMap.put("number", number);
        String site = sensor.getDevice().getPoint().getLon() + " " + sensor.getDevice().getPoint().getLat();
        returnMap.put("site", site);
        //赋值 传感器历史数据流程
        returnMap.put("grid", handleHistoryArr(id, sensorType, begin, end));
        return returnMap;
    }


    @Autowired
    private RedisDBService redisDBService;

    /**
     * 代码思路：
     * 将不同时间的同一项数据叠加到一起，并记录最开始时间，根据一分钟一条数据即可得到所有数据和对应时间关系数组，
     * 然后再根据检测项进行和数据值进行遍历实现gridList结构
     *
     * @param id         传感器id
     * @param sensorType 传感器类型
     * @return
     */
    public List<Map<String, Object>> handleHistoryArr(Long id, String sensorType, String begin, String end) {
        HashSet<String> itemSet = new HashSet();//存储不同项的类型set
        JSONObject dataItemJson = new JSONObject();//存储不同项的开始计算时间戳和历史数据arr以及单位
        //获取某sensor的历史数据
        Map sqlPlaceholder = new HashMap();

        StringBuilder sql = new StringBuilder("select a.item_value_arr,a.date,b.item_name,b.item_unit " +
                "from slope_item_history a " +
                "LEFT JOIN slope_monitor_item b on a.item_id = b.item_id where b.sensor_id = :id");
        sqlPlaceholder.put("id", id);
        if (!begin.equals("") && !end.equals("")) {
            sql.append(" and a.date>= :begin and a.date <= :end");
            sqlPlaceholder.put("begin", begin);
            sqlPlaceholder.put("end", end);
//            sql += " and a.date>='" + begin + "' and a.date <='" + end + "' ";
        }
        List<HistoryResult> historyList = jdbcTemplate.query(sql.toString(), sqlPlaceholder, BeanPropertyRowMapper.newInstance(HistoryResult.class));

        //将数据补齐，暂不考虑缓存跨天的场景
        SlopeSensor slopeSensor = slopeSensorService.selectSlopeSensorById(id);
        String imei = slopeSensor.getDevice().getImei();
        List<HistoryResult> backList = new ArrayList<>();

        Date date1 = new Date();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date1);
        int curIndex = calendar.get(Calendar.HOUR_OF_DAY) * 60 + calendar.get(Calendar.MINUTE);

        for (int k = 0; k < historyList.size(); ++k) {
            HistoryResult historyResult = historyList.get(k);
//            Map<String, Object> historyItem = historyList.get(k);
            String date = new SimpleDateFormat("yyyy-MM-dd").format(historyResult.getDate());
            String[] strArr = historyResult.getItemValueArr().split(",");
            String itemName = historyResult.getItemName();
            Map redisData = redisDBService.getItemHistoryData(imei, itemName);
            JSONObject js = (JSONObject) redisData.get(date);
            if (js != null) {
                for (String timeIndex : js.keySet()) {
                    strArr[Integer.valueOf(timeIndex)] = String.valueOf(js.getFloat(timeIndex));
                }
                String newArrStr = "";
                int realLen = strArr.length > curIndex + 1 ? curIndex + 1 : strArr.length;          //取较小者
                for (int i = 0; i < realLen; ++i) {
                    String s = (strArr[i] == null ? "null" : strArr[i]) + (i == realLen - 1 ? "" : ",");
                    newArrStr += s;
                }
                historyResult.setItemValueArr(newArrStr);
            }
            //截断当天数据
            else {
                if (date.equals(new SimpleDateFormat("yyyy-MM-dd").format(new Date()))) {
                    String newArrStr = "";
                    int realLen = strArr.length > curIndex + 1 ? curIndex + 1 : strArr.length;          //取较小者
                    for (int i = 0; i < realLen; ++i) {
                        String s = (strArr[i] == null ? "null" : strArr[i]) + (i == realLen - 1 ? "" : ",");
                        newArrStr += s;
                    }
                    historyResult.setItemValueArr(newArrStr);
                }
            }
            backList.add(historyResult);
        }
        historyList = backList;

        for (int i = 0; i < historyList.size(); i++) {
            HistoryResult history = historyList.get(i);
            String itemName = history.getItemName();
//            Long timestamp = DateUtils.dateTime("yyyy-MM-dd", json.getString("date")).getTime() / 1000;
            Long timestamp = history.getDate().getTime() / 1000;
            itemSet.add(itemName);
            //判断是否有最开始时间
            if (!dataItemJson.containsKey(itemName + "_startTime")) {
                dataItemJson.put(itemName + "_startTime", timestamp);
            }
            String itemUnit = history.getItemUnit();
            //判断是否有该监测项单位
            if (!dataItemJson.containsKey(itemName + "_unit")) {
                dataItemJson.put(itemName + "_unit", itemUnit);
            }
            String dataArr = history.getItemValueArr();

            //判断存储数据arr的json中是否包含此arr，并将arr填充进数据
            if (dataItemJson.containsKey(itemName)) {
                JSONArray arr = dataItemJson.getJSONArray(itemName);
                for (String str : dataArr.split(",")) {
                    arr.add(str);
                }
                dataItemJson.put(itemName, arr);
            } else {
                JSONArray arr = new JSONArray();
                for (String str : dataArr.split(",")) {
                    arr.add(str);
                }
                dataItemJson.put(itemName, arr);
            }

        }
        return handleHistoryGridData(itemSet, sensorType, dataItemJson);
    }


    public List<Map<String, Object>> handleHistoryArrByItem(Long id, String sensorType, String begin, String end) {
        HashSet<String> itemSet = new HashSet();//存储不同项的类型set
        JSONObject dataItemJson = new JSONObject();//存储不同项的开始计算时间戳和历史数据arr以及单位
        //获取某sensor的历史数据
        Map sqlPlaceholder = new HashMap();
        StringBuilder sql = new StringBuilder("select a.item_value_arr,a.date,b.item_name,b.item_unit from slope_item_history a LEFT JOIN slope_monitor_item b on a.item_id = b.item_id where b.item_id =:id ");
        sqlPlaceholder.put("id", id);
        if (!begin.equals("") && !end.equals("")) {
            sql.append(" and a.date >= :begin and a.date <= :end ");
            sqlPlaceholder.put("begin", begin);
            sqlPlaceholder.put("end", end);
        }
        List<HistoryResult> historyList = jdbcTemplate.query(sql.toString(), sqlPlaceholder, BeanPropertyRowMapper.newInstance(HistoryResult.class));
//        for (int i = 0; i < historyList.size(); i++) {
//            Map<String, Object> history = historyList.get(i);
//            JSONObject json = new JSONObject(history);
//            String itemName = json.getString("item_name");
//            Long timestamp = DateUtils.dateTime("yyyy-MM-dd", json.getString("date")).getTime() / 1000;
//            itemSet.add(itemName);
//            //判断是否有最开始时间
//            if (!dataItemJson.containsKey(itemName + "_startTime")) {
//                dataItemJson.put(itemName + "_startTime", timestamp);
//            }
//            String itemUnit = json.getString("item_unit");
//            //判断是否有该监测项单位
//            if (!dataItemJson.containsKey(itemName + "_unit")) {
//                dataItemJson.put(itemName + "_unit", itemUnit);
//            }
//            String dataArr = json.getString("item_value_arr");
//
//            //判断存储数据arr的json中是否包含此arr，并将arr填充进数据
//            if (dataItemJson.containsKey(itemName)) {
//                JSONArray arr = dataItemJson.getJSONArray(itemName);
//                for (String str : dataArr.split(",")) {
//                    arr.add(str);
//                }
//                dataItemJson.put(itemName, arr);
//            } else {
//                JSONArray arr = new JSONArray();
//                for (String str : dataArr.split(",")) {
//                    arr.add(str);
//                }
//                dataItemJson.put(itemName, arr);
//            }
//
//        }
        for (int i = 0; i < historyList.size(); i++) {
            HistoryResult history = historyList.get(i);
            String itemName = history.getItemName();
//            Long timestamp = DateUtils.dateTime("yyyy-MM-dd", json.getString("date")).getTime() / 1000;
            Long timestamp = history.getDate().getTime() / 1000;
            itemSet.add(itemName);
            //判断是否有最开始时间
            if (!dataItemJson.containsKey(itemName + "_startTime")) {
                dataItemJson.put(itemName + "_startTime", timestamp);
            }
            String itemUnit = history.getItemUnit();
            //判断是否有该监测项单位
            if (!dataItemJson.containsKey(itemName + "_unit")) {
                dataItemJson.put(itemName + "_unit", itemUnit);
            }
            String dataArr = history.getItemValueArr();

            //判断存储数据arr的json中是否包含此arr，并将arr填充进数据
            if (dataItemJson.containsKey(itemName)) {
                JSONArray arr = dataItemJson.getJSONArray(itemName);
                for (String str : dataArr.split(",")) {
                    arr.add(str);
                }
                dataItemJson.put(itemName, arr);
            } else {
                JSONArray arr = new JSONArray();
                for (String str : dataArr.split(",")) {
                    arr.add(str);
                }
                dataItemJson.put(itemName, arr);
            }

        }
        return handleHistoryGridData(itemSet, sensorType, dataItemJson);
    }

    /**
     * 将数据根据时间统一到grid map中生产页面需要的grid结构
     *
     * @param itemSet      检测类型项set
     * @param sensorType   传感器类型
     * @param dataItemJson 历史数据及检测项单位和数据开始最小时间戳
     * @return
     */
    public List<Map<String, Object>> handleHistoryGridData(HashSet<String> itemSet, String sensorType, JSONObject dataItemJson) {
        List<Map<String, Object>> gridList = new LinkedList<>();//单个item的grid数组
        //根据item项取出最小时间作为初始时间标准，取数据数组最大的长度作为循环截止数，若其他项无数据作为无效值计算设为0
        Long minTime = 0L;
        int maxLen = 0;
        for (String str : itemSet) {
            if (minTime == 0) {
                minTime = dataItemJson.getLong(str + "_startTime");
            } else {
                minTime = minTime < dataItemJson.getLong(str + "_startTime") ? minTime : dataItemJson.getLong(str + "_startTime");
            }
            if (maxLen == 0) {
                maxLen = dataItemJson.getJSONArray(str).size();
            } else {
                maxLen = maxLen > dataItemJson.getJSONArray(str).size() ? maxLen : dataItemJson.getJSONArray(str).size();
            }
        }
        for (int i = 0; i < maxLen; i++) {
            Map<String, Object> grid = new HashMap<>();//单个grid对象
            grid.put("time", DateUtils.timeStamp2Date((minTime + i * 60) + "", "yyyy-MM-dd HH:mm"));
            for (String str : itemSet) {
                if (dataItemJson.getJSONArray(str).size() > i) {
                    String data = dataItemJson.getJSONArray(str).getString(i);
                    if (data.equals("null")) {
                        grid.put(str, null);
                    } else {
                        grid.put(str, data);
                    }
                } else {
                    grid.put(str, null);
                }
            }
            gridList.add(grid);
        }
        return gridList;
    }

    /**
     * 导出监测项历史数据列表
     */
    @ApiOperation("导出监测项历史数据列表")
    @Log(title = "监测管理", businessType = BusinessType.EXPORT)
    @GetMapping("/export")
    @PreAuthorize("@ss.hasPermi('slope:history:export')")
    public AjaxResult export(SlopeItemHistory slopeItemHistory) {
        List<SlopeItemHistory> list = slopeItemHistoryService.selectSlopeItemHistoryList(slopeItemHistory);
        ExcelUtil<SlopeItemHistory> util = new ExcelUtil<SlopeItemHistory>(SlopeItemHistory.class);
        return util.exportExcel(list, "history");
    }

    /**
     * 导出数据报表
     */
    @ApiOperation("导出数据报表")
    @Log(title = "监测管理", businessType = BusinessType.EXPORT)
    @GetMapping("/exportReport")
    @PreAuthorize("@ss.hasPermi('slope:history:exportReport')")
    public AjaxResult exportReport(SlopeItemHistory slopeItemHistory) throws ParseException {
        slopeItemHistory.setEndTime(slopeItemHistory.getEndTime() + " 23:59:59");
        List<SlopeItemHistory> list = slopeItemHistoryService.selectSlopeItemHistoryList2(slopeItemHistory);
        List<SlopeDataReport> dataList = new LinkedList<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        List<Long> itemIds = new ArrayList<>();
        String beginTime = slopeItemHistory.getBeginTime() + " 00:00:00";
        for (SlopeItemHistory itemHistory : list) {
            if (itemIds.contains(itemHistory.getItemId())) {
                beginTime = sdf.format(new Date(sdf.parse(beginTime).getTime() + 1000 * 60 * 60 * 24));
            } else {
                itemIds.add(itemHistory.getItemId());
                beginTime = slopeItemHistory.getBeginTime() + " 00:00:00";
            }
            SlopeMonitorItem item = itemHistory.getItem();
            SlopeSensor sensor = item.getSensor();
            SlopeDevice device = sensor.getDevice();
            SlopeDataReport report = new SlopeDataReport();
            report.setId(item.getItemId());
            report.setContent(sensor.getMonitorDetail());
            report.setMeasuringName(device.getPoint().getPointName());
            report.setEquipmentType(sensor.getSensorType().getTypeName());
            report.setEquipmentName(device.getDeviceName());
            report.setProject(item.getItemName());
            report.setSite(device.getPoint().getLon() + "," + device.getPoint().getLat());
            report.setStatus(getDeviceState(device.getState()));
            report.setDetectionValue(item.getItemValue() + item.getItemUnit());
            List<StringBuilder> itemValueArr = getStringBuildersJson(slopeItemHistory, sdf, itemHistory, beginTime);
            report.setItemValueArr(JSON.toJSONString(itemValueArr));
            dataList.add(report);
        }
        ExcelUtil<SlopeDataReport> util = new ExcelUtil<>(SlopeDataReport.class);
        return util.exportExcel(dataList, "history");
    }

    private List<StringBuilder> getStringBuildersJson(SlopeItemHistory slopeItemHistory, SimpleDateFormat sdf, SlopeItemHistory itemHistory, String beginTime) throws ParseException {
        String[] parse = itemHistory.getItemValueArr().split(",");
        List<StringBuilder> itemValueArr = new ArrayList<>();
        Date startDateTime = sdf.parse(beginTime);
        for (String value : parse) {
            if (!value.equals("null")) {
                StringBuilder jsonMap = new StringBuilder();
                jsonMap
                        .append("{'time':")
                        .append(sdf.format(startDateTime.getTime() + 1000 * 60))
                        .append(",'value':")
                        .append(value)
                        .append("}");
                itemValueArr.add(jsonMap);
            }
            startDateTime = new Date(startDateTime.getTime() + 1000 * 60);
        }
        return itemValueArr;
    }

    /**
     * 获取监测项历史数据详细信息
     */
    @ApiOperation("获取监测项历史数据详细信息")
    @GetMapping(value = "/getInfo/{itemHistoryId}")
    @PreAuthorize("@ss.hasPermi('slope:history:getInfo')")
    public AjaxResult getInfo(@PathVariable("itemHistoryId") Long itemHistoryId) {
        return AjaxResult.success(slopeItemHistoryService.selectSlopeItemHistoryById(itemHistoryId));
    }

    /**
     * 新增监测项历史数据
     */
    @ApiOperation("新增监测项历史数据")
    @Log(title = "监测管理", businessType = BusinessType.INSERT)
    @PostMapping("/add")
    @PreAuthorize("@ss.hasPermi('slope:history:add')")
    public AjaxResult add(@RequestBody SlopeItemHistory slopeItemHistory) {
        return toAjax(slopeItemHistoryService.insertSlopeItemHistory(slopeItemHistory));
    }

    /**
     * 修改监测项历史数据
     */
    @ApiOperation("修改监测项历史数据")
    @Log(title = "监测管理", businessType = BusinessType.UPDATE)
    @PostMapping("/updateHistory")
    @PreAuthorize("@ss.hasPermi('slope:history:updateHistory')")
    public AjaxResult updateHistory(@RequestBody SlopeItemHistory slopeItemHistory) {
        return toAjax(slopeItemHistoryService.updateSlopeItemHistory(slopeItemHistory));
    }

    /**
     * 删除监测项历史数据
     */
    @ApiOperation("删除监测项历史数据")
    @Log(title = "监测管理", businessType = BusinessType.DELETE)
    @PostMapping("/remove/{itemHistoryIds}")
    @PreAuthorize("@ss.hasPermi('slope:history:remove')")
    public AjaxResult remove(@PathVariable Long[] itemHistoryIds) {
        return toAjax(slopeItemHistoryService.deleteSlopeItemHistoryByIds(itemHistoryIds));
    }

    @Autowired
    private ISysDictDataService dictDataService;

    public String getDeviceState(Integer state) {
        List<SysDictData> list = dictDataService.selectDictDataByType("sensor_state");
        for (SysDictData dictData : list) {
            if ((state + "").equals(dictData.getDictValue())) {
                return dictData.getDictLabel();
            }
        }
        return null;
    }
}
